// 编译期 if 语句（C++17 的 if constexpr）
// C++17 引入了 if constexpr 语法，它允许在编译期间根据条件选择性地编译代码，这对模板实例化有重要影响。

// 基本语法
if constexpr (编译期常量表达式)
{
    // 如果条件为真，这部分代码会被编译
}
else
{
    // 如果条件为假，这部分代码会被丢弃，不会生成任何代码
}

// ------------------------------------------------
// 与普通 if 的区别
// 普通 if：条件在运行时求值，两个分支都会被编译，只是运行时决定执行哪个。
// if constexpr：条件在编译期求值，不满足条件的分支会被完全丢弃，不会生成任何代码。
if (true)
{
    // 分支 A
}
else
{
    // 分支 B
}
// 编译行为：编译器会编译两个分支的代码，即使条件是常量 true。

// ------------------------------------------------
// 例子：递归计算阶乘
// 使用 if constexpr 的递归阶乘模板
template <typename T>
constexpr T factorial(T n)
{
    if constexpr (std::is_integral_v<T>)
    {
        // 整数类型的实现
        if (n <= 1)
            return 1;
        return n * factorial(n - 1);
    }
    else
    {
        // 非整数类型，编译期报错
        static_assert(false, "factorial only works with integral types");
        return T{}; // 这行代码永远不会被编译
    }
}

// ------------------------------------------------
// 对模板实例化的影响
// if constexpr 对模板实例化有两个重要影响：
// 1.选择性实例化：只有满足条件的分支会被实例化，不满足条件的分支不会生成代码。
// 2.避免无效代码：在不满足条件的分支中，即使有无法编译的代码（如对不支持的类型的操作），也不会导致编译错误。

// ------------------------------------------------
// 更复杂的例子：类型特化处理
template <typename T>
void process(T value)
{
    if constexpr (std::is_pointer_v<T>)
    {
        // 指针类型的处理
        std::cout << "Pointer value: " << *value << std::endl;
    }
    else if constexpr (std::is_array_v<T>)
    {
        // 数组类型的处理
        for (const auto &elem : value)
        {
            std::cout << elem << " ";
        }
        std::cout << std::endl;
    }
    else
    {
        // 其他类型的处理
        std::cout << "Value: " << value << std::endl;
    }
}
// 使用：
int x = 42;
int *p = &x;
int arr[] = {1, 2, 3};

process(x);   // 输出: Value: 42
process(p);   // 输出: Pointer value: 42
process(arr); // 输出: 1 2 3

// --------------------------------------------------------
// 与 SFINAE 的比较
// 在 C++17 之前，类似的功能通常使用 SFINAE（Substitution Failure Is Not An Error）实现，比如：
// C++17 之前的方式
template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
factorial(T n)
{
    if (n <= 1)
        return 1;
    return n * factorial(n - 1);
}

template <typename T>
typename std::enable_if<!std::is_integral<T>::value, T>::type
factorial(T)
{
    static_assert(false, "factorial only works with integral types");
    return T{};
}
// if constexpr 使代码更简洁、更易读，减少了模板元编程的复杂度。

// --------------------------------------------------------
// 总结
// if constexpr 是 C++17 引入的编译期条件语句。
// 它允许根据编译期常量表达式选择性地实例化模板代码。
// 不满足条件的分支会被完全丢弃，不会生成代码，也不会导致编译错误。
// 这大大简化了模板编程，使代码更清晰、更易维护。
